﻿using System;
using System.Collections.Generic;
using System.Reflection;

namespace Com.OpenCode.Framework.Core
{
    /// <summary>
    ///     Class解析器。
    /// </summary>
    public class ClassDoozer : IDoozer
    {
        /// <summary>
        ///     解析器名称。
        /// </summary>
        public string Name
        {
            get { return "Class"; }
        }

        public object BuildItem(BuildItemEventArgs args)
        {
            object obj = null;
            if (Name == args.Plugin.Name)
            {
                string className = args.Plugin.Properties.GetString("Type");
                obj = args.Plugin.Addin.Runtime.CreateObject(className);
                foreach (KeyValuePair<object, object> keyValuePair in args.Plugin.Properties.Dictionary)
                {
                    try
                    {
                        if (keyValuePair.Key.ToString().StartsWith("Pro."))
                        {
                            string fieldName = keyValuePair.Key.ToString().Split('.')[1];
                            SetValue(obj, fieldName, args.Plugin.Properties.GetString(keyValuePair.Key));
                        }
                        else if (keyValuePair.Key.ToString().StartsWith("Ref."))
                        {
                            string fieldName = keyValuePair.Key.ToString().Split('.')[1];
                            object refObj = args.Plugin.Addin.Bulid(Name, "Id", keyValuePair.Value.ToString(), null);
                            SetValue(obj, fieldName, refObj);
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new Exception(string.Format("创建对象失败{0}，请检查{1}节点配置。",ex.Message, className));
                    }
                }
            }
            else
            {
                throw new Exception(string.Format("{0}解析器无法解析插件节点{1}，请使用正确的解析器。", Name, args.Plugin.Name));
            }
            return obj;
        }

        public void SetValue(object entity, object fieldName, object fieldValue)
        {
            Type entityType = entity.GetType();
            PropertyInfo propertyInfo = entityType.GetProperty(fieldName.ToString());
            if (propertyInfo == null)
            {
                throw new Exception(string.Format("对象{0}不包含名称为{1}的属性。", entity, fieldName));
            }
            if (IsType(propertyInfo.PropertyType, "System.String"))
            {
                propertyInfo.SetValue(entity, fieldValue, null);
            }
            else if (IsType(propertyInfo.PropertyType, "System.Boolean"))
            {
                propertyInfo.SetValue(entity, bool.Parse(fieldValue.ToString()), null);
            }
            else if (IsType(propertyInfo.PropertyType, "System.Int32"))
            {
                if (!string.IsNullOrEmpty(fieldValue.ToString()))
                {
                    propertyInfo.SetValue(entity, int.Parse(fieldValue.ToString()), null);
                }
                else
                {
                    propertyInfo.SetValue(entity, 0, null);
                }
            }
            else if (IsType(propertyInfo.PropertyType, "System.Decimal"))
            {
                if (!string.IsNullOrEmpty(fieldValue.ToString()))
                {
                    propertyInfo.SetValue(entity, decimal.Parse(fieldValue.ToString()), null);
                }
                else
                {
                    propertyInfo.SetValue(entity, new decimal(0), null);
                }
            }
            else if (IsType(propertyInfo.PropertyType, "System.Nullable`1[System.DateTime]"))
            {
                if (!string.IsNullOrEmpty(fieldValue.ToString()))
                {
                    try
                    {
                        propertyInfo.SetValue(entity, (DateTime?) DateTime.ParseExact(fieldValue.ToString(), "yyyy-MM-dd HH:mm:ss", null), null);
                    }
                    catch
                    {
                        propertyInfo.SetValue(entity, (DateTime?) DateTime.ParseExact(fieldValue.ToString(), "yyyy-MM-dd", null), null);
                    }
                }
                else
                {
                    propertyInfo.SetValue(entity, null, null);
                }
            }
            else
            {
                propertyInfo.SetValue(entity, fieldValue, null);
            }
        }

        public bool IsType(Type type, string typeName)
        {
            if (type.ToString() == typeName)
                return true;
            if (type.ToString() == "System.Object")
                return false;
            return IsType(type.BaseType, typeName);
        }

        public static object BulidItem(Addin addin, string Id)
        {
            Plugin plugin = addin.Plugin.Search("Class", "Id", Id);
            if (plugin != null)
            {
                return plugin.Addin.Bulid(plugin);
            }
            return null;
        }

    }
}